

// time.cpp


/*
 * This header contains two classes that deal with time. Everything
 * is encapsulated in the Time namespace just to keep things clean
 * and prevent any possible naming convention ambiguities.
 *
 * One is clock, which handles timekeeping and such. Also featured
 * with the clock class, there is implementation for a 'tick'
 * system. Meaning, once set up, every x seconds you can call
 * a certain function. That's in addition to traditional time
 * keeping functions, like GetTime(), GetDate(), etc.
 *
 * The other class is stopwatch, which can keep track of elapsed
 * time since started, or can count down for a given length of
 * time. Status of whether or not 'time is up' can be accessed
 * using CheckUp() (for stopwatch functions) or CheckDown() (which
 * is used for countdowns).
 *
 * Sorry, but I don't go into a lot of detail as to how everything
 * works exactly. It was amazingly tedious to write, and 99 percent
 * of the code is simply converting between different forms of the
 * same time data. For example, taking the number of seconds since
 * 00:00:00 01/01/1970 and converting to a string of the current
 * date.
 *
 */

#ifndef CPP_TIME
#define CPP_TIME

#include< time.h >
#include< iostream >

namespace Time {
	unsigned int Rand( unsigned int a, unsigned int b );
	bool Default( void );

	class clock {
		private:
			// Data...
			__time64_t _time;
			__time64_t _fire;
			__time64_t _nextfire;
			__time64_t _sw_start;
			__time64_t _sw_end;

			char _ctime[9];
			unsigned int _itime[3];
			char _tcfire[9];
			unsigned int _tifire[3];

			char _cdate[9];
			unsigned int _idate[3];
			char _dcfire[9];
			unsigned int _difire[3];

			// Methods...
			void Parse( char*, unsigned int* );
			void PrivateFire( unsigned int, unsigned int );
			void PrivateFire( unsigned int );
			void PrivateFire( void );

		public:
			// Constructors
			clock();
			clock( bool (*fptr) ( void ) );
			~clock();

			// Data...
			bool (*Execute) ( void );

			// Methods...
			int Update();
			bool Check();
			void Fire( unsigned int a, unsigned int b );
			void Fire( unsigned int );
			void Fire( void );
			void SetNextFire( unsigned int );

			char* GetTime();
			unsigned int GetSeconds();
			unsigned int GetMinutes();
			unsigned int GetHours();

			char* GetDate();
			unsigned int GetDay();
			unsigned int GetMonth();
			unsigned int GetYear();
	};

	class stopwatch {
		private:
			bool _on;
			__time64_t _time;
			__time64_t _start;
			__time64_t _cache;
			__time64_t _ustart;
			__time64_t _uend;
			__time64_t _dstart;
			__time64_t _dend;

		public:
			stopwatch::stopwatch();
			stopwatch::stopwatch( stopwatch& );
			stopwatch::~stopwatch();

			void Update();

			void Start();
			unsigned int Watch();
			unsigned int Stop();
			unsigned int Cache();

			void StartUp( unsigned int a );
			unsigned int Up();
			bool CheckUp();
			void ResetUp( unsigned int a );

			void StartDown( unsigned int a );
			unsigned int Down();
			bool CheckDown();
			void ResetDown( unsigned int a );
	};
}

unsigned int Time::Rand( unsigned int a, unsigned int b ) {
	// Returns an unsigned int between a and b.
	if ( a == 0 )
		b++;
	return ( (rand() % b) + a );
}

bool Time::Default( void ) {
	// This is the default function for the clock::Fire functions.
	// To customize: see footnote.
	char temp[] = "00:00:00";
	std::cout << "\n\n--== TICK ==--\n\t" << _strtime( temp ) << std::endl;
	return true;
}

Time::clock::clock() {
	// Default constructor
	_time64( &_time );
	_time64( &_fire );
	_nextfire = 0;

	// Time...
	Parse( _strtime( _ctime ), _itime );
	Parse( _strtime( _tcfire ), _tifire );

	// Date...
	Parse( _strdate( _cdate ), _idate );
	Parse( _strdate( _dcfire ), _difire );

	Execute = Default;
}

Time::clock::clock( bool (*fptr) ( void ) ) {
	_time64( &_time );
	_time64( &_fire );
	_nextfire = 0;

	// Time...
	Parse( _strtime( _ctime ), _itime );
	Parse( _strtime( _tcfire ), _tifire );

	// Date...
	Parse( _strdate( _cdate ), _idate );
	Parse( _strdate( _dcfire ), _difire );

	Execute = fptr;
}

Time::clock::~clock() { }

void Time::clock::Parse( char* time, unsigned int* target ) {
	char temp[3] = { '\0', '\0', '\0' };
	temp[0] = time[0];
	temp[1] = time[1];
	target[0] = atoi( temp );
	temp[0] = time[3];
	temp[1] = time[4];
	target[1] = atoi( temp );
	temp[0] = time[6];
	temp[1] = time[7];
	target[2] = atoi( temp );

	return;
}

void Time::clock::PrivateFire( unsigned int a, unsigned int b ) {
	_time64( &_fire );
	Parse( _strtime( _tcfire ), _tifire );
	Parse( _strdate( _dcfire ), _difire );
	SetNextFire( Rand( a, b ) );
	return;
}

void Time::clock::PrivateFire( unsigned int a ) {
	_time64( &_fire );
	Parse( _strtime( _tcfire ), _tifire );
	Parse( _strdate( _dcfire ), _difire );
	SetNextFire( a );
	return;
}

void Time::clock::PrivateFire( void ) {
	_time64( &_fire );
	Parse( _strtime( _tcfire ), _tifire );
	Parse( _strdate( _dcfire ), _difire );
	SetNextFire( -1 );
	return;
}

int Time::clock::Update() {
	_time64( &_time );
	_strtime( _ctime );
	Parse( _ctime, _itime );
	_strdate( _cdate );
	Parse( _cdate, _idate );
	return 0;
}

bool Time::clock::Check() {
	this->Update();
	if ( _time >= _nextfire )
		 return true;
	return false;
}

void Time::clock::Fire( unsigned int a, unsigned int b ) {
	PrivateFire( a, b );
	Execute();

	return;
}

void Time::clock::Fire( unsigned int a ) {
	PrivateFire( a );
	Execute();

	return;
}

void Time::clock::Fire( void ) {
	PrivateFire();
	Execute();

	return;
}

void Time::clock::SetNextFire( unsigned int seconds ) {
	this->Update();

	_time64( &_nextfire );
	_nextfire += seconds;

	void PrivateFire();

	return;
}

char* Time::clock::GetTime() {
	this->Update();
	return _ctime;
}

unsigned int Time::clock::GetSeconds() {
	this->Update();
	return _itime[2];
}

unsigned int Time::clock::GetMinutes() {
	this->Update();
	return _itime[1];
}

unsigned int Time::clock::GetHours() {
	this->Update();
	return _itime[0];
}

char* Time::clock::GetDate() {
	this->Update();
	return _cdate;
}

unsigned int Time::clock::GetDay() {
	this->Update();
	return _idate[1];
}

unsigned int Time::clock::GetMonth() {
	this->Update();
	return _idate[0];
}

unsigned int Time::clock::GetYear() {
	this->Update();
	return _idate[2];
}

Time::stopwatch::stopwatch() {
	_on = false;
	_time = 0;
	_start = 0;
	_cache = 0;
	_ustart = 0;
	_uend = 0;
	_dstart = 0;
	_dend = 0;
}

Time::stopwatch::stopwatch( stopwatch& it ) {
	_on = it._on;
	_time = it._time;
	_start = it._start;
	_cache = it._cache;
	_ustart = it._ustart;
	_uend = it._uend;
	_dstart = it._dstart;
	_dend = it._dend;
}

Time::stopwatch::~stopwatch() {
}

void Time::stopwatch::Update() {
	_time64( &_time );
	return;
}

void Time::stopwatch::Start() {
	_on = true;
	this->Update();
	_time64( &_start );
	_cache = 0;
	return;
}

unsigned int Time::stopwatch::Watch() {
	if ( _on ) {
		this->Update();
		return (unsigned int)(_time - _start);
	}
	else
		return 0;
}

unsigned int Time::stopwatch::Stop() {
	_on = false;
	this->Update();
	_cache = (unsigned int)(_time - _start);
	return (unsigned int)_cache;
}

unsigned int Time::stopwatch::Cache() {
	return (unsigned int)_cache;
}

void Time::stopwatch::StartUp( unsigned int a ) {
	this->Update();
	_time64( &_ustart );
	_uend = _ustart + a;
	return;
}

unsigned int Time::stopwatch::Up() {
	this->Update();
	return (unsigned int)(_time - _ustart);
}

bool Time::stopwatch::CheckUp() {
	this->Update();
	if ( _time >= _uend )
		return false;
	else
		return true;
}

void Time::stopwatch::ResetUp( unsigned int a ) {
	this->StartUp( a );
}

void Time::stopwatch::StartDown( unsigned int a ) {
	this->Update();
	_time64( &_dstart );
	_dend = _dstart + a;
}

unsigned int Time::stopwatch::Down() {
	this->Update();
	return (unsigned int)(_dend - _time);
}

bool Time::stopwatch::CheckDown() {
	this->Update();
	if ( _time >= _dend )
		return false;
	else
		return true;
}

void Time::stopwatch::ResetDown( unsigned int a ) {
	this->StartDown( a );
}



/*int main() { // This is kept here just for the ease of testing/debuggin.
	return 0;
}*/



#endif // #ifndef CPP_TIME